<template>
  <div class="form-part" :style="{
    width: width
  }">
    <el-form :rules="rules" ref="formRef" :model="formData" :label-width="labelWidth + 'px' ">
      <el-form-item v-for="(item, index) in hiddenInput " v-show="false" :prop="item.name" :label="item.label">
        <el-input type="text" :key="index"
                  v-model="formData[item.name]" @input="$forceUpdate()"></el-input>
      </el-form-item>
      <el-row v-for="(rowItem,rowIndex) in inputData " :gutter="gutter">
        <el-col v-for="(item,colIndex) in rowItem" :span="colSpan * item.colSpan!">
          <el-form-item :prop="item.name" :label="item.label" v-if="hasComponent(true ,item.name)">
            <el-input ref="refs" @blur="inputBlur(item.name)" :size="getInputSize(item.inputSize)"
                      :style="{
                        width: isEmpty(item.inputWidth ) ? '100%' : item.inputWidth
                      }"
                      v-if="hasComponent(item.type.includes('input') ,item.name)"
                      v-show="item.type != FormItemType.INPUT_HIDDEN"
                      :placeholder="item.placeholder"
                      v-for="(value,key) in getProperty(item)"
                      :[key]="value"
                      :type="getInputType(item)"
                      v-model="formData[item.name]" @input="$forceUpdate()"></el-input>

            <el-select @change="inputBlur(item.name)" ref="refs" :multiple="item.isMultiple"
                       :size="getInputSize(item.inputSize)" v-for="(value,key) in getProperty(item)"
                       :[key]="value" v-model="formData[item.name]" @input="$forceUpdate()"
                       v-if="hasComponent(item.type == FormItemType.SELECT ,item.name)">
              <el-option v-for="(option,index) in item.options" :label="option.text" :value="option.value"></el-option>
            </el-select>

            <Component ref="customerRefs" @customize-change="customizeChange"
                     v-if="hasComponent(item.type == FormItemType.CUSTOMIZE_SELECT,item.name) "
                       v-bind="item" :is="h(CustomizeSelect,{...$attrs,...props},$slots)" ></Component>

            <Component ref="customerRefs" @customize-change="customizeChange"
                       v-if="hasComponent(item.type == FormItemType.SEARCH_SELECT,item.name) "
                       v-bind="item" :is="h(SearchSelect,{...$attrs,...props},$slots)" ></Component>

            <Component ref="customerRefs"  @customize-change="customizeChange"  v-bind="item"
                       v-if="hasComponent(item.type == FormItemType.DIC_SELECT,item.name) "
                       :is="h(DicSelect,{...$attrs,...props},$slots)" ></Component>

            <el-radio-group ref="refs" :size="getInputSize(item.inputSize)" v-for="(value,key) in getProperty(item)"
                            :[key]="value" v-model="formData[item.name]" @input="$forceUpdate()"
                            v-if="hasComponent(item.type == FormItemType.RADIO,item.name) ">
              <el-radio v-for="(option,index) in item.options" :label="option.text" :value="option.value"></el-radio>
            </el-radio-group>

            <el-checkbox-group ref="refs" :size="getInputSize(item.inputSize)" v-for="(value,key) in getProperty(item)"
                               :[key]="value" v-model="formData[item.name]" @input="$forceUpdate()"
                               v-if="hasComponent(item.type == FormItemType.CHECKBOX,item.name)">
              <el-checkbox v-for="(option,index) in item.options" :label="option.text" :value="option.value"
                           @input="$forceUpdate()"/>
            </el-checkbox-group>

            <el-config-provider ref="refs" :locale="locale" v-if="hasComponent(item.type == 'picker',item.name) ">
              <el-date-picker :style="{
                width: '100%'
              }" :size="getInputSize(item.inputSize)" v-for="(value,key) in getProperty(item)"
                              :[key]="value" v-model="formData[item.name]" @input="$forceUpdate()"></el-date-picker>
            </el-config-provider>

            <slot :name="item.name" v-if="hasComponent(item.type == FormItemType.SLOT,item.name)"></slot>
          </el-form-item>
        </el-col>
      </el-row>
      <div class="footer">
        <el-button type="primary" v-if="showSubmit" @click="submitForm">提交</el-button>
        <el-button v-if="showReset" @click="executeResetForm">重置</el-button>
      </div>
    </el-form>
  </div>
</template>
<style scoped>
.footer {
  text-align: right;
}
</style>

<script setup lang="ts">
import {computed, getCurrentInstance, h, nextTick, onMounted, onUpdated, reactive, ref, toRaw, toRef} from "vue";
import {FormItemType, type FormView} from "@/components/plugs/form/DialogFormInterface.ts";
import zhCn from "element-plus/es/locale/lang/zh-cn";
import CustomizeSelect from "@/components/plugs/form/CustomizeSelect.vue";
import {ElMessage, ElMessageBox} from "element-plus";
import {isEmpty} from "lodash";
import DicSelect from "@/components/plugs/form/DicSelect.vue";
import CustomizeSelectDemo from "@/components/plugs/form/CustomizeSelectDemo.vue";
import SearchInput from "@/components/plugs/input/SearchInput.vue";
import SearchSelect from "@/components/plugs/select/SearchSelect.vue";

let locale = zhCn;
const emits = defineEmits(['validateSuccess', 'loadSuccess', 'updateDataSuccess']);

const props = withDefaults(defineProps<FormView>(), {
  splitCol: 1, //分割表单为4列
  gutter: 20,
  labelWidth: 100,
  inputSize: 'default',
  width: '100%',
  hasShow: true,
  showSubmit: true,
  showReset: true,
  dataChange: (oldValue: object, newValue: object, field: string) => {
  },
  rules: () => {
    return {}
  },
  items: () => []
});
const vm = getCurrentInstance();
const {splitCol, items, gutter, rules, dataChange, inputSize} = props;
const inputValue = ref('');
const formRef = ref({});
const formData: any = reactive({});
const lastFormData: any = reactive({});
const test = ref(null);
const refs: any = ref([]);
const customerRefs: any = reactive([]);
const hiddenInput: any = reactive([]);

items.forEach((item, index) => {
  const temp = toRaw(item);
  formData[temp.name] = temp.defaultValue;
  lastFormData[temp.name] = {
    value: temp.defaultValue,
    hasShow: temp.hasShow == undefined ? true : temp.hasShow
  }
});

const getInputType = (item: { [key: string]: any }) => {
  if (item.type == FormItemType.INPUT_HIDDEN) {
    return 'text';
  }
  return item.type.substring(item.type.indexOf('input') + 6, item.type.length);
}

const hasComponent = (exist: boolean, filed: string) => {
  return exist && lastFormData[filed].hasShow;
}

const inputBlur = (field: string) => {
  dataChange(lastFormData[field].value, formData[field], field);
  lastFormData[field].value = formData[field];
}

const customizeChange = (field: string, value: any) => {
  lastFormData[field].value = formData[field];
  formData[field] = value;
  dataChange(lastFormData[field].value, formData[field], field);
}

const getInputSize = (itemInputSize: any) => {
  return (itemInputSize == null || itemInputSize == undefined) ? inputSize : itemInputSize;
}

//处理行列问题
const colSpan = computed(() => {
  return Math.floor(24 / toRaw(splitCol));
});
const inputData = computed(() => {
  let result = [];
  let temp = [];
  let num = 0;
  for (let i = 0; i < items.length; i++) {
    if (items[i].type == FormItemType.INPUT_HIDDEN) {
      hiddenInput.push(items[i]);
      continue;
    }
    temp.push(items[i]);
    items[i].colSpan = (items[i].colSpan == undefined || items[i].colSpan == null) ? 1 : items[i].colSpan;
    num += items[i].colSpan!;
    if (num == splitCol || i == items.length - 1) {
      result.push(temp);
      temp = [];
      num = 0;
    }
  }
  return result;
});

const getProperty = (item: any) => {
  return (item.property == undefined || item.property == null) ? {"key": "value"} : item.property;
}

const selectChange = (value: any, field: string) => {
  let vm = test;
  formData[field] = value;
}

const instance = getCurrentInstance()
const executeResetForm = () => {
  let vm = instance;
  ElMessageBox.confirm(
      '是否重置表单?',
      '提示',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(() => {
    console.log('确认');
    resetForm();
  }).catch(() => {
    console.log('取消')
  });
}

const resetForm = () => {
  nextTick(() => {
    let v = formData;
    formRef.value.resetFields();
    customerRefs.forEach((item: object, index: number) => {
       item.resetFields();
    });
  });
}

const submitForm = () => {

  formRef.value.validate((valid: boolean, fields: { [key: string]: any }) => {
    if (valid) {
      const tempFormData = toRaw(formData);
      let validateData: any = {};
      for (const key in tempFormData) {
        const val = tempFormData[key];
        if (key.indexOf(".") != -1) {
          const keys: any = key.split(".");
          setNestedProperty(validateData, keys, val);
        } else {
          validateData[key] = val;
        }
      }
      console.log("validateData: ", validateData);
      emits('validateSuccess', validateData);
    } else {
      ElMessage.info("表单验证不通过！【" + fields[Object.keys(fields)[0]][0].message + "】");
    }
  });
};


const setNestedProperty = (obj: { [key: string]: any }, keys: [], value: any) => {
  keys.reduce((acc, key, index, arr) => {
    if (index === arr.length - 1) { // 最后一个键，设置值
      acc[key] = value;
    } else { // 不是最后一个键，继续深入对象
      acc[key] = acc[key] || {};
    }
    return acc[key];
  }, obj);
}

onMounted(() => {
  emits("loadSuccess");
});

onUpdated(() => {
  emits("updateDataSuccess");
});

//暴露方法
const getFormData = () => {
  return toRaw(formData);
}

const setData = (data: any) => {
  nextTick(() => {
    debugger;
    for (const key in formData) {
      let val = data[key];
      if (key.indexOf(".") != -1) {
        val = key.split('.').reduce((acc, part) => acc && acc[part], data);
      }
      formData[key] = val;
      lastFormData[key] = {
        value: val,
        hasShow: true
      }
    }
    customerRefs.forEach((item: any) => {
      const field = item.getField();
      item.setData(formData[field]);
    });
    triggerChange();
  });
}


const init = () => {
  for (const key in formData) {
    formData[key] = '';
  }
}

const triggerChange = () => {
  for (const key in lastFormData) {
    dataChange(lastFormData[key], formData[key], key);
  }
}

const triggerField = (fields: [], state?: boolean) => {
  if( fields == undefined || fields == null || fields.length <= 0){
    for(const key in lastFormData){
      lastFormData[key]!.hasShow = (state == undefined || state == null) ? !lastFormData[field]?.hasShow : state;
    }
    return;
  }
  for (const field of fields) {
    lastFormData[field]!.hasShow = (state == undefined || state == null) ? !lastFormData[field]?.hasShow : state;
  }
}

const triggerAllField = (state?: boolean) => {
  for(const key in lastFormData){
    lastFormData[key]!.hasShow = (state == undefined || state == null) ? !lastFormData[field]?.hasShow : state;
  }
}

defineExpose({getFormData, setData, init, resetForm, triggerField,triggerAllField});

</script>